/*
 *  Copyright 2016 http://www.kedacomframework.org
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *
 */

package com.kedacom.ctsp.authz.oauth2.service;

import com.kedacom.ctsp.authority.entity.Person;
import com.kedacom.ctsp.authority.entity.User;
import com.kedacom.ctsp.authority.service.UserService;
import com.kedacom.ctsp.authz.entity.AuthUser;
import com.kedacom.ctsp.authz.entity.Authentication;
import com.kedacom.ctsp.authz.exception.UnauthorizedException;
import com.kedacom.ctsp.authz.exception.UsernameNotFoundException;
import com.kedacom.ctsp.authz.oauth2.core.ErrorType;
import com.kedacom.ctsp.authz.oauth2.core.OAuth2Exception;
import com.kedacom.ctsp.authz.oauth2.entity.Client;
import com.kedacom.ctsp.authz.oauth2.entity.SimpleClient;
import com.kedacom.ctsp.lang.RandomUtil;
import com.kedacom.ctsp.lang.StringUtil;
import com.kedacom.ctsp.orm.param.Term;
import com.kedacom.ctsp.web.entity.DataStatus;
import com.kedacom.ctsp.web.entity.param.QueryParamEntity;
import com.kedacom.ctsp.web.service.StatusEnum;
import com.kedacom.ctsp.web.service.simple.AbstractCrudEntityService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Service;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import java.util.stream.Collectors;

import static com.kedacom.ctsp.web.entity.StatefulBean.STATUS;

/**
 * TODO 完成注释
 *
 * @author zhouhao
 */
public class ClientServiceImpl extends AbstractCrudEntityService<Client, String> implements ClientService {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private UserService userService;

    protected Client checkClient(Client client) {
        if (client == null) {
            throw new OAuth2Exception(ErrorType.CLIENT_NOT_EXIST);
        }
        if (!Objects.equals(DataStatus.STATUS_ENABLED, client.getStatus() == null ? null : client.getStatus().byteValue())) {
            throw new OAuth2Exception(ErrorType.CLIENT_DISABLED);
        }
        return client;
    }

    /**
     * 根据项目标识获取项目信息
     *
     * @param sign
     * @return
     */
    @Override
    public Client getClient(String sign) {
        if (StringUtils.isBlank(sign)) {
            return null;
        }
        return createQuery().where(Client.SIGN, sign).single();
    }

    @Override
    public Client getCheckedClientByOwnerId(Long ownerId, String clientId) {
        List<Client> clients = getClientByOwnerId(ownerId);
        if (clients == null) {
            return null;
        }
        List<Client> list = clients.stream().filter(client -> {
            if (client.getId().equalsIgnoreCase(clientId)) {
                return true;
            } else {
                return false;
            }
        }).collect(Collectors.toList());
        if (list != null && list.size() > 0) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public Client getCheckedClient(String sign) {
        return checkClient(getClient(sign));
    }

    /**
     * 通过拥有人获取项目信息
     *
     * @param ownerId
     * @return
     */
    @Override
    public List<Client> getClientByOwnerId(Long ownerId) {
        return createQuery().where(Client.OWNER_ID, ownerId).listNoPaging();
    }

    /**
     * 判断client是否合法
     *
     * @param sign
     * @param clientSecret
     * @throws OAuth2Exception
     */
    @Override
    public void validateClient(String sign, String clientSecret) throws OAuth2Exception {
        Client client = getClient(sign);
        if (client != null) {
            if (!client.getSecret().equalsIgnoreCase(clientSecret)) {
                throw new OAuth2Exception(ErrorType.ILLEGAL_CLIENT_SECRET);
            }
        }
    }

    @Override
    public String insert(Client entity) {
        if (entity.getStatus() == null) {
            entity.setStatus(StatusEnum.ENABLE.ordinal());
        }
        Authentication authentication = Authentication.current().orElseThrow(UnauthorizedException::new);
        AuthUser authUser = authentication.getUser();
        if (authUser != null) {
            entity.setOwnerId(authUser.getId());
        }
        return super.insert(entity);
    }

    /**
     * 更新项目列表
     *
     * @param id
     * @param entity
     * @return
     */
    public int updateForProject(String id, Client entity) {
        return jdbcTemplate.update("UPDATE `transition_project` SET  `name`=?, `redirect_uri`=?, `sign`=?, `default_grant_scope`=?, `support_grant_types`=?, `f_client_describe`=? WHERE `id`=?",
                entity.getName(), entity.getRedirectUri(), entity.getSign(), entity.getDefaultGrantScope(), entity.getSupportGrantTypes(), entity.getDescribe(), id);
    }

    /**
     * 获取项目列表
     *
     * @param param
     * @return
     */
    @Override
    public List<Client> listForProject(QueryParamEntity param) {
        List<Object> queryList = new ArrayList<Object>();
        StringBuffer fullSql = new StringBuffer(" select id,name,mark as sign from f_project where status=1 and examined_state=3 ");
        List<Term> terms = param.getTerms();
        if (CollectionUtils.isNotEmpty(terms)) {
            fullSql.append(" where ");
            terms.stream().forEach(term -> {
                fullSql.append(term.getColumn()).append(" like ? ");
                queryList.add("%" + term.getValue() + "%");
            });
        }
        List<Client> list = jdbcTemplate.query(fullSql.toString(), queryList.toArray(), new BeanPropertyRowMapper(SimpleClient.class));
        if (list != null && list.size() > 0) {
            return list;
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public List<Long> addUserClient(Long id, List<String> clients) {
        deletebyUser(id);
        if (clients == null) {
            return null;
        }
        List<Long> userClientIds = new ArrayList<>();
        KeyHolder keyHolder = new GeneratedKeyHolder();
        clients.forEach(s -> {

            try {
                jdbcTemplate.update(new PreparedStatementCreator() {
                    @Override
                    public PreparedStatement createPreparedStatement(Connection con)
                            throws SQLException {
                        PreparedStatement ps = jdbcTemplate.getDataSource()
                                .getConnection().prepareStatement("INSERT INTO `f_user_project` ( `user_id`, `client_id`) VALUES (?, ?)", Statement.RETURN_GENERATED_KEYS);

                        ps.setObject(1, id);
                        ps.setObject(2, s);

                        return ps;
                    }
                }, keyHolder);
            } catch (DataAccessException e) {

                e.printStackTrace();
            }
            userClientIds.add(keyHolder.getKey().longValue());


        });
        return userClientIds;
    }

    @Override
    public List<Client> getUserClient(String username) {
        // 用户不存在
        User user = userService.selectByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException();
        }
        //List<Client> strings = jdbcTemplate.query("select project_mark sign from r_project_person where user_name= ? ", new Object[]{username}, new BeanPropertyRowMapper(SimpleClient.class));
        // if (strings == null || strings.size() == 0) {
        //     return new ArrayList<>();
        //  }
        //
        //List<Client> list = this.createQuery().in(Client.SIGN, strings).and().where(STATUS, StatusEnum.ENABLE.ordinal()).listNoPaging();
        List<Client> list = jdbcTemplate.query("select id,name,mark as sign from f_project where status=1 and  exists  (select project_mark from r_project_person where user_name= ? and r_project_person.project_mark=f_project.mark)", new Object[]{username}, new BeanPropertyRowMapper(SimpleClient.class));
        if (list != null && list.size() > 0) {
            return list;
        } else {
            return new ArrayList<>();
        }
    }

    /**
     * 根据id,和项目id删除项目信息
     *
     * @param id
     * @param clients
     */
    private void deletebyUserClient(Long id, List<String> clients) {
        NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);

        Map<String, Object> params = new HashMap<>();
        params.put("id", id);
        params.put("clients", clients);
        namedParameterJdbcTemplate.update("DELETE FROM f_user_project where user_id=:id and client_id in(:clients)", params);
    }

    /**
     * 根据用户id,删除项目信息
     *
     * @param id
     */
    private void deletebyUser(Long id) {
        jdbcTemplate.update("DELETE FROM f_user_project where user_id=? ", id);
    }
}
